﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Cci;
using Microsoft.Cci.MutableCodeModel;

namespace Mutator
{
    class ExpressionMutantRetriever : Microsoft.Cci.MutableCodeModel.MethodBodyCodeMutator
    {
  
        
        public int counter = 0;
        public HashSet<int> visitedHash;
        public bool mutated=false;
        Random rand = new Random();
        public ExpressionMutantRetriever(IMetadataHost host)
            : base(host)
        {
            
        }
        public ExpressionMutantRetriever(IMetadataHost host, ISourceLocationProvider/*?*/ sourceLocationProvider)
            : base(host,sourceLocationProvider)
        {

        }
        
        public override IExpression Visit(Multiplication multiplication)
        {
            
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                BinaryOperation newOp1 = new Addition();
                newOp1.LeftOperand = multiplication.LeftOperand;
                newOp1.RightOperand = multiplication.RightOperand;
                mutated = true;
                return this.Visit((BinaryOperation)newOp1);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                BinaryOperation newOp2 = new Subtraction();
                newOp2.LeftOperand = multiplication.LeftOperand;
                newOp2.RightOperand = multiplication.RightOperand;
                mutated = true;
                return this.Visit((BinaryOperation)newOp2);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                BinaryOperation newOp3 = new Modulus();
                newOp3.LeftOperand = multiplication.LeftOperand;
                newOp3.RightOperand = multiplication.RightOperand;
                mutated = true;
                return this.Visit((BinaryOperation)newOp3);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                BinaryOperation newOp4 = new Division();
                newOp4.LeftOperand = multiplication.LeftOperand;
                newOp4.RightOperand = multiplication.RightOperand;
                mutated = true;
                return this.Visit((BinaryOperation)newOp4);
            }
            
            return this.Visit((BinaryOperation)multiplication);
        }
        public override IExpression Visit(Division division)
        {
            counter++;
            if (!mutated&&visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                BinaryOperation newOp1 = new Addition();
                newOp1.LeftOperand = division.LeftOperand;
                newOp1.RightOperand = division.RightOperand;
                mutated = true;
                return this.Visit((BinaryOperation)newOp1);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                BinaryOperation newOp2 = new Subtraction();
                newOp2.LeftOperand = division.LeftOperand;
                newOp2.RightOperand = division.RightOperand;
                mutated = true;
                return this.Visit((BinaryOperation)newOp2);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                BinaryOperation newOp3 = new Modulus();
                newOp3.LeftOperand = division.LeftOperand;
                newOp3.RightOperand = division.RightOperand;
                mutated = true;
                return this.Visit((BinaryOperation)newOp3);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                BinaryOperation newOp4 = new Multiplication();
                newOp4.LeftOperand = division.LeftOperand;
                newOp4.RightOperand = division.RightOperand;
                mutated = true;
                return this.Visit((BinaryOperation)newOp4);
            }

            return this.Visit((BinaryOperation)division);
        }
        public override IExpression Visit(Addition addition)
        {
             counter++;
             if (!mutated && visitedHash.Contains(counter))
             {
                 visitedHash.Remove(counter);
                 BinaryOperation newOp1 = new Multiplication();
                 newOp1.LeftOperand = addition.LeftOperand;
                 newOp1.RightOperand = addition.RightOperand;
                 mutated = true;
                 return this.Visit((BinaryOperation)newOp1);
             }
             counter++;
             if (!mutated && visitedHash.Contains(counter))
             {
                 visitedHash.Remove(counter);
                 BinaryOperation newOp2 = new Subtraction();
                 newOp2.LeftOperand = addition.LeftOperand;
                 newOp2.RightOperand = addition.RightOperand;
                 mutated = true;
                 return this.Visit((BinaryOperation)newOp2);
             }
             counter++;
             if (!mutated && visitedHash.Contains(counter))
             {
                 visitedHash.Remove(counter);
                 BinaryOperation newOp3 = new Modulus();
                 newOp3.LeftOperand = addition.LeftOperand;
                 newOp3.RightOperand = addition.RightOperand;
                 mutated = true;
                 return this.Visit((BinaryOperation)newOp3);
             }
             counter++;
             if (!mutated && visitedHash.Contains(counter))
             {
                 visitedHash.Remove(counter);
                 BinaryOperation newOp4 = new Division();
                 newOp4.LeftOperand = addition.LeftOperand;
                 newOp4.RightOperand = addition.RightOperand;
                 mutated = true;
                 return this.Visit((BinaryOperation)newOp4);
             }

          
            return this.Visit((BinaryOperation)addition);
        }
        public override IExpression Visit(Subtraction subtraction)
        {
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                BinaryOperation newOp1 = new Addition();
                newOp1.LeftOperand = subtraction.LeftOperand;
                newOp1.RightOperand = subtraction.RightOperand;
                mutated = true;
                return this.Visit((BinaryOperation)newOp1);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                BinaryOperation newOp2 = new Multiplication();
                newOp2.LeftOperand = subtraction.LeftOperand;
                newOp2.RightOperand = subtraction.RightOperand;
                mutated = true;
                return this.Visit((BinaryOperation)newOp2);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                BinaryOperation newOp3 = new Modulus();
                newOp3.LeftOperand = subtraction.LeftOperand;
                newOp3.RightOperand = subtraction.RightOperand;
                mutated = true;
                return this.Visit((BinaryOperation)newOp3);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                BinaryOperation newOp4 = new Division();
                newOp4.LeftOperand = subtraction.LeftOperand;
                newOp4.RightOperand = subtraction.RightOperand;
                mutated = true;
                return this.Visit((BinaryOperation)newOp4);
            }

            
            return this.Visit((BinaryOperation)subtraction);
        }
        public override IExpression Visit(Modulus modulus)
        {
             counter++;
             if (!mutated && visitedHash.Contains(counter))
             {
                 visitedHash.Remove(counter);
                 BinaryOperation newOp1 = new Addition();
                 newOp1.LeftOperand = modulus.LeftOperand;
                 newOp1.RightOperand = modulus.RightOperand;
                 mutated = true;
                 return this.Visit((BinaryOperation)newOp1);
             }
             counter++;
             if (!mutated && visitedHash.Contains(counter))
             {
                 visitedHash.Remove(counter);
                 BinaryOperation newOp2 = new Subtraction();
                 newOp2.LeftOperand = modulus.LeftOperand;
                 newOp2.RightOperand = modulus.RightOperand;
                 mutated = true;
                 return this.Visit((BinaryOperation)newOp2);
             }
             counter++;
             if (!mutated && visitedHash.Contains(counter))
             {
                 visitedHash.Remove(counter);
                 BinaryOperation newOp3 = new Multiplication();
                 newOp3.LeftOperand = modulus.LeftOperand;
                 newOp3.RightOperand = modulus.RightOperand;
                 mutated = true;
                 return this.Visit((BinaryOperation)newOp3);
             }
             counter++;
             if (!mutated && visitedHash.Contains(counter))
             {
                 visitedHash.Remove(counter);
                 BinaryOperation newOp4 = new Division();
                 newOp4.LeftOperand = modulus.LeftOperand;
                 newOp4.RightOperand = modulus.RightOperand;
                 mutated = true;
                 return this.Visit((BinaryOperation)newOp4);
             }

              return this.Visit((BinaryOperation)modulus);
        }
        
        public override IExpression Visit(BitwiseAnd bitwiseAnd)
        {
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                BinaryOperation newOp1 = new BitwiseOr();
                newOp1.RightOperand = bitwiseAnd.RightOperand;
                newOp1.LeftOperand = bitwiseAnd.LeftOperand;
                mutated = true;
                return this.Visit((BinaryOperation)newOp1);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                BinaryOperation newOp2 = new ExclusiveOr();
                newOp2.RightOperand = bitwiseAnd.RightOperand;
                newOp2.LeftOperand = bitwiseAnd.LeftOperand;
                mutated = true;
                return this.Visit((BinaryOperation)newOp2);
            }
            return this.Visit((BinaryOperation)bitwiseAnd);
        }
        public override IExpression Visit(BitwiseOr bitwiseOr)
        {
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                BinaryOperation newOp1 = new BitwiseAnd();
                newOp1.RightOperand = bitwiseOr.RightOperand;
                newOp1.LeftOperand = bitwiseOr.LeftOperand;
                mutated = true;
                return this.Visit((BinaryOperation)newOp1);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                BinaryOperation newOp2 = new ExclusiveOr();
                newOp2.RightOperand = bitwiseOr.RightOperand;
                newOp2.LeftOperand = bitwiseOr.LeftOperand;
                mutated = true;
                return this.Visit((BinaryOperation)newOp2);
            }

            return this.Visit((BinaryOperation)bitwiseOr);
        }
        public override IExpression Visit(ExclusiveOr exclusiveOr)
        {
             counter++;
             if (!mutated && visitedHash.Contains(counter))
             {
                 visitedHash.Remove(counter);
                 BinaryOperation newOp1 = new BitwiseOr();
                 newOp1.RightOperand = exclusiveOr.RightOperand;
                 newOp1.LeftOperand = exclusiveOr.LeftOperand;
                 mutated = true;
                 return this.Visit((BinaryOperation)newOp1);
             }
             counter++;
             if (!mutated && visitedHash.Contains(counter))
             {
                 visitedHash.Remove(counter);
                 BinaryOperation newOp2 = new BitwiseAnd();
                 newOp2.RightOperand = exclusiveOr.RightOperand;
                 newOp2.LeftOperand = exclusiveOr.LeftOperand;
                 mutated = true;
                 return this.Visit((BinaryOperation)newOp2);
             }


            return this.Visit((BinaryOperation)exclusiveOr);
        }
        public override IExpression Visit(BinaryOperation operation)
        {
            
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                CompileTimeConstant newOp1 = new CompileTimeConstant();
                newOp1.Value = rand.Next(1, int.MaxValue);
                mutated = true;
                return this.Visit(newOp1);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                CompileTimeConstant newOp2 = new CompileTimeConstant();
                newOp2.Value = 0;
                mutated = true;
                return this.Visit(newOp2);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                CompileTimeConstant newOp3 = new CompileTimeConstant();
                newOp3.Value = rand.Next(int.MinValue, 0);
                mutated = true;
                return this.Visit(newOp3);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                UnaryOperation newOp4 = new UnaryNegation();
                newOp4.Operand = operation;
                mutated = true;
                return this.Visit(newOp4);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                UnaryOperation newOp5 = new UnaryPlus();
                newOp5.Operand = operation;
                mutated = true;
                return this.Visit(newOp5);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                UnaryOperation newOp6 = new OnesComplement();
                newOp6.Operand = operation;
                mutated = true;
                return this.Visit(newOp6);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                UnaryOperation newOp7 = new LogicalNot();
                newOp7.Operand = operation;
                mutated = true;
                return this.Visit(newOp7);
            }
            return operation;
        }

        public override IExpression Visit(UnaryOperation operation)
        {
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
               
                CompileTimeConstant newOp1 = new CompileTimeConstant();
                newOp1.Value = rand.Next(1, int.MaxValue);
                mutated = true;
                return this.Visit(newOp1);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                CompileTimeConstant newOp2 = new CompileTimeConstant();
                newOp2.Value = 0;
                mutated = true;
                return this.Visit(newOp2);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                CompileTimeConstant newOp3 = new CompileTimeConstant();
                newOp3.Value = rand.Next(int.MinValue, 0);
                mutated = true;
                return this.Visit(newOp3);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                UnaryOperation newOp4 = new UnaryNegation();
                newOp4.Operand = operation;
                mutated = true;
                return this.Visit(newOp4);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                UnaryOperation newOp5 = new UnaryPlus();
                newOp5.Operand = operation;
                mutated = true;
                return this.Visit(newOp5);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                UnaryOperation newOp6 = new OnesComplement();
                newOp6.Operand = operation;
                mutated = true;
                return this.Visit(newOp6);
            }
            counter++;
            if (!mutated && visitedHash.Contains(counter))
            {
                visitedHash.Remove(counter);
                UnaryOperation newOp7 = new LogicalNot();
                newOp7.Operand = operation;
                mutated = true;
                return this.Visit(newOp7);
            }
            return operation;

        }
        
        
        
    }
}